﻿using System;

namespace Trentacular.Office.Server.Search.FacetedSearch.Providers
{
    /// <summary>
    /// A facet provider implementation that aggregates
    /// <see cref="T:System.DateTime" /> managed properties into month ranges.
    /// </summary>
    public class DateTimeManagedPropertyFacetBuilder
        : BaseManagedPropertyFacetBuilder<DateTime>
    {
        /// <summary>
        /// The key name of the month display date format configuration property.
        /// </summary>
        public const string MonthDisplayDateFormatKey = "MonthDisplayDateFormat";

        /// <summary>
        /// The default month display date format string value.
        /// </summary>
        public const string DefaultMonthDisplayDateFormat = "MMMM, yyyy";

        /// <summary>
        /// The date format string used to format the start and end month values to be
        /// used within the facet's filter string.
        /// </summary>
        public const string FilterStringDateFormat = "yyyy/MM/dd HH:mm:ss";

        private string _monthDisplayDateFormat;

        /// <summary>
        /// Gets the date format string used to format the month value for the facet's
        /// display name.
        /// </summary>
        /// <value>The date format string used to format the month value for the
        /// facet's display name.</value>
        protected virtual string MonthDisplayDateFormat
        {
            get
            {
                if (_monthDisplayDateFormat == null)
                    _monthDisplayDateFormat =
                        LoadMonthDisplayDateFormatFromConfiguration();
                return _monthDisplayDateFormat;
            }
        }

        /// <summary>
        /// Loads the month display date format from the facet provider configuration.
        /// </summary>
        /// <returns>If found, the month display date format string from the facet
        /// provider configuration; otherwise the default month display date format
        /// string.</returns>
        protected string LoadMonthDisplayDateFormatFromConfiguration()
        {
            var monthDisplayDateFormat =
                Configuration.Properties[MonthDisplayDateFormatKey];

            if (string.IsNullOrEmpty(monthDisplayDateFormat))
                return DefaultMonthDisplayDateFormat;

            return monthDisplayDateFormat;
        }

        /// <summary>
        /// Indicating whether the <see cref="ManagedPropertyFacetProvider"/> should
        /// sort the resulting facets by their keys.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if the <see cref="ManagedPropertyFacetProvider"/>
        /// should sort the resulting facets by their keys; otherwise, <c>false</c>.
        /// </value>
        public override bool SortByKey { get { return true; } }

        /// <summary>
        /// Gets the facet keys for a single search result's managed property value.
        /// </summary>
        /// <param name="value">The facet keys for a single search result's managed
        /// property value.</param>
        /// <returns>An array of keys.</returns>
        public override string[] GetKeys(DateTime value)
        {
            var key = value.Year * 100 + value.Month;
            return new[] { key.ToString() };
        }

        /// <summary>
        /// Creates a facet for a given facet key and managed property value.
        /// </summary>
        /// <param name="key">The facet's key.</param>
        /// <param name="value">The managed property value.</param>
        /// <returns>The generated facet.</returns>
        public override Facet CreateFacet(string key, DateTime value)
        {
            var startMonth = new DateTime(value.Year, value.Month, 1);
            var endMonth = startMonth.AddMonths(1);
            return new Facet(
                FacetedSearchContext,
                Configuration,
                key,
                value.ToString(this.MonthDisplayDateFormat),
                string.Format("({0} > '{1}' And {0} < '{2}')",
                    ManagedPropertyName,
                    startMonth.ToString(FilterStringDateFormat),
                    endMonth.ToString(FilterStringDateFormat)
                    )
            );
        }
    }
}
